package com.ejiaoyi.common.util;

import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

/**
 * DES 加解密工具类
 *
 * @author unknownChivalrous
 * @since 2020-4-21
 */
@Slf4j
public class DesUtil {

    /**
     * 密钥因子 必须是8的倍数
     */
    private static final String DES_KEY = "3955C482C8C85B4CA8C9D8D4987F8B7F";
    private static final String DES = "DES";

    /**
     * 加密
     *
     * @param src 数据源
     * @param key 密钥，长度必须是8的倍数
     * @return 返回加密后的数据
     * @throws Exception 异常
     */
    public static byte[] encrypt(byte[] src, byte[] key) throws Exception {
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(key);

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey secretKey = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance(DES);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr);
        return cipher.doFinal(src);
    }

    /**
     * 解密
     *
     * @param src 数据源
     * @param key 密钥，长度必须是8的倍数
     * @return 返回解密后的原始数据
     * @throws Exception 异常
     */
    public static byte[] decrypt(byte[] src, byte[] key) throws Exception {
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(key);

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey secretKey = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance(DES);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, sr);

        return cipher.doFinal(src);
    }

    /**
     * 加密 使用默认密钥
     *
     * @param src 数据源
     * @return 返回加密后的数据
     */
    public static String encrypt(String src) {
        Assert.notEmpty(src, "param src can not be empty");

        try {
            return byte2hex(encrypt(src.getBytes(), DES_KEY.getBytes()));
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        return null;
    }

    /**
     * 解密 使用默认密钥
     *
     * @param src 数据源
     * @return 返回解密后的数据
     */
    public static String decrypt(String src) {
        Assert.notEmpty(src, "param src can not be empty");

        try {
            return new String(decrypt(hex2byte(src), DES_KEY.getBytes()), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        return null;
    }

    /**
     * 二进制转字符串
     *
     * @param bytes 二进制
     * @return 字符串
     */
    public static String byte2hex(byte[] bytes) {
        Assert.notNull(bytes, "param bytes can not be null");

        StringBuilder hs = new StringBuilder();
        String stmp = "";
        for (byte b : bytes) {
            stmp = (Integer.toHexString(b & 0XFF));
            if (stmp.length() == 1) {
                hs.append("0").append(stmp);
            } else {
                hs.append(stmp);
            }
        }

        return hs.toString().toUpperCase();
    }

    /**
     * 字符串转二进制
     *
     * @param str 字符串
     * @return 二进制
     */
    public static byte[] hex2byte(String str) {
        Assert.notEmpty(str, "param str can not be empty");

        byte[] bytes = str.getBytes();
        if ((bytes.length % 2) != 0) {
            throw new IllegalArgumentException("长度不是偶数");
        }
        byte[] b2 = new byte[bytes.length / 2];
        for (int n = 0; n < bytes.length; n += 2) {
            String item = new String(bytes, n, 2);
            b2[n / 2] = (byte) Integer.parseInt(item, 16);
        }
        return b2;
    }
}
